package com.link.serve.tcp;// 服务端
import com.link.serve.constants.LinkConstant;
import com.link.serve.tcp.encoder.MessageDecoder;
import com.link.serve.tcp.encoder.MessageEncoder;
import com.link.serve.tcp.handler.NettyServerHandler;
import com.link.serve.tcp.handler.TokenValidationHandler;
import com.link.serve.tcp.handler.UplinkMessageHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * TCP服务器,用于连接网页的客户端,协议格式参考这里https://www.yuque.com/u2071973/gsrdze/nidvg485l8fwviuk
 * @author xiaojie
 * @date 2025-01-20
 */
@Slf4j
@Component
@ConditionalOnProperty(prefix = "tcp", value = "enable", havingValue = "true", matchIfMissing = true)
public class TcpServer implements LinkServer{

    @Value("${tcp.port}")
    private int port;

    //开启状态
    private volatile boolean ready = false;

    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;
    @Override
    public boolean isReady() {
        return ready;
    }

    @Override
    public void start() {
        int bossThreads = Math.max(1, Runtime.getRuntime().availableProcessors() / 4); // 设置为 CPU 核心数的 1/4
        int workerThreads = Runtime.getRuntime().availableProcessors() * 2; // 设置为 CPU 核心数的 2 倍
        ServerBootstrap bootstrap = new ServerBootstrap();
        bossGroup = new NioEventLoopGroup(bossThreads);//主线程组，负责接收客户端连接请求。
        workerGroup = new NioEventLoopGroup(workerThreads);//工作线程组，负责处理连接的读写和业务逻辑。
        //设置为主从线程模型 多Reactor多线程模型
        bootstrap.group(bossGroup, workerGroup) // 配置主线程组和工作线程组
                .channel(NioServerSocketChannel.class) // 指定服务端使用的通道类型
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline() // 获取管道
                                .addLast(new IdleStateHandler(LinkConstant.ONLINE_TIMEOUT_SECOND, 0, 0, TimeUnit.SECONDS))//空闲状态监测
                                .addLast(new MessageDecoder()) // 添加自定义解码器
                                .addLast(new TokenValidationHandler()) // 添加 Token 校验处理器
                                //判断bizId=IM handler（对应服务进行推送（消息体（压缩））过去）
                                .addLast(new UplinkMessageHandler())//是否需要上行业务推送
                                .addLast(new MessageEncoder()) // 添加自定义编码器
                                .addLast(new NettyServerHandler()); // 添加业务逻辑处理器
                    }
                })// 表示连接保活，相当于心跳机制，默认为7200s
                .childOption(ChannelOption.SO_KEEPALIVE, true);
        try {
            // 绑定端口，启动select线程，轮询监听channel事件，监听到事件之后就会交给从线程池处理
            bootstrap.bind(port).sync().channel();
            // 就绪标志
            this.ready = true;
            log.info("tcp server 初始化完成,端口：{}", port);
        } catch (InterruptedException e) {
            log.info("tcp server 初始化异常", e);
        }
    }

    @Override
    public void stop() {
        if (bossGroup != null && !bossGroup.isShuttingDown() && !bossGroup.isShutdown()) {
            bossGroup.shutdownGracefully();
        }
        if (workerGroup != null && !workerGroup.isShuttingDown() && !workerGroup.isShutdown()) {
            workerGroup.shutdownGracefully();
        }
        this.ready = false;
        log.info("tcp server 停止");
    }
}